﻿using System;
using System.IO;
using System.Threading;
using System.Windows.Forms;

namespace ClientSocket
{
    public partial class Form_main : Form, IClientSocket
    {
        public Form_main()
        {
            InitializeComponent();
        }

        #region 内部变量
        private const string versionCode = "0.5";
        private bool isBegin, isHeart;
        private ClientSocket clientSocket;
        private string path = System.Environment.CurrentDirectory + "\\log";
        private DateTime lastReadDateTime, lastWriteDateTime, lastSendHeartDateTime;
        #endregion

        #region 委托
        private delegate void SetTextCallBack(bool isSend, string operate, string content);
        private SetTextCallBack setTextCallBack;
        private delegate void SetButtonCallBack(bool enable);
        private SetButtonCallBack setButtonCallBack;
        private delegate void SetLastDateTimeCallBack(Label label, int type, DateTime dateTime);
        private SetLastDateTimeCallBack setLastDateTimeCallBack;
        #endregion

        /// <summary>
        /// 最后时间
        /// </summary>
        /// <param name="label">显示Label控件</param>
        /// <param name="type">-1:最后读、0：最后写、1：最后心跳</param>
        private void SetLastDateTime(Label label, int type, DateTime dateTime)
        {
            if (!label.InvokeRequired)
            {
                switch (type)
                {
                    case -1:
                        this.lastReadDateTime = dateTime;
                        break;
                    case 0:
                        this.lastWriteDateTime = dateTime;
                        break;
                    default:
                        this.lastSendHeartDateTime = dateTime;
                        break;
                }
                label.Text = dateTime.ToLongTimeString();
            }
            else
            {
                label.Invoke(setLastDateTimeCallBack, new object[] { label, type, dateTime });
            }
        }

        private void Ini()
        {
            setTextCallBack = new SetTextCallBack(SetValue);
            setButtonCallBack = new SetButtonCallBack(ChangeButton);
            setLastDateTimeCallBack = new SetLastDateTimeCallBack(SetLastDateTime);

            this.comboBox1.SelectedIndex = 0;
            this.comboBox2.SelectedIndex = 0;
            this.comboBox3.SelectedIndex = 3;
            this.textBox4.Text = this.GetGuid();
            this.textBox4.ReadOnly = true;
            this.textBox3.Text = "group1";

            this.checkBox3.Checked = true;
            ChangeLastLabel();
        }

        private void SetListView()
        {
            #region 设置
            this.listView1.FullRowSelect = true;
            this.listView1.GridLines = true;
            this.listView1.CheckBoxes = false;
            this.listView1.MultiSelect = false;
            this.listView1.SmallImageList = this.imageList1;
            this.listView1.HoverSelection = true;
            this.listView1.UseCompatibleStateImageBehavior = false;
            this.listView1.View = View.Details;
            #endregion

            #region 加入自定义列
            this.listView1.Columns.Clear();
            ColumnHeader columnHeader = new ColumnHeader();
            columnHeader.Text = "操作";
            columnHeader.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
            columnHeader.Width = 55;
            this.listView1.Columns.Add(columnHeader);

            ColumnHeader columnHeader1 = new ColumnHeader();
            columnHeader1.Text = "时间";
            columnHeader1.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
            columnHeader1.Width = 60;
            this.listView1.Columns.Add(columnHeader1);
            ColumnHeader columnHeader2 = new ColumnHeader();
            columnHeader2.Text = "消息内容";
            columnHeader2.TextAlign = System.Windows.Forms.HorizontalAlignment.Left;
            columnHeader2.Width = 460;
            this.listView1.Columns.Add(columnHeader2);
            #endregion
        }

        private string GetGuid()
        {
            string guid = Guid.NewGuid().ToString().Replace("-", "");
            if (guid.Length > 30)
                return guid.Substring(0, 30);
            else
                return guid;
        }

        private void ChangeLastLabel()
        {
            this.label11.Text = null;
            this.label13.Text = null;
            this.label15.Text = null;
        }
        private void ChangeButton(bool enable)
        {
            if (!this.InvokeRequired)
            {
                this.button1.Enabled = enable;
                this.textBox1.Enabled = enable;
                this.numericUpDown1.Enabled = enable;

                this.button2.Enabled = !enable;
                this.button3.Enabled = !enable;
                this.button7.Enabled = !enable;
                this.button8.Enabled = !enable;
                this.button9.Enabled = !enable;
                this.button10.Enabled = !enable;
                if (!enable)
                {
                    this.button10.Text = "发出心跳";
                    this.isHeart = false;
                }
                this.textBox2.Enabled = !enable;
                this.checkBox1.Enabled = !enable;
                this.numericUpDown2.Enabled = !enable;
                this.textBox3.Enabled = !enable;
                this.comboBox2.Enabled = !enable;
                this.comboBox3.Enabled = !enable;
                isBegin = !enable;
            }
            else
            {
                this.Invoke(setButtonCallBack, new object[] { enable });
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Ini();
            SetListView();
            string fileName = "SocketParamer";
            string path = System.Environment.CurrentDirectory;
            path = string.Format("{0}\\{1}.xml", path, fileName);
            if (File.Exists(path))
            {
                SocketConnectModel socketConnectModel = XmlUtil.XmlSerialObject<SocketConnectModel>(path);
                if (socketConnectModel != null)
                {
                    this.textBox1.Text = socketConnectModel.ip;
                    this.numericUpDown1.Value = socketConnectModel.port;
                }
            }

            this.Text = string.Format("SOCKET客户端组件工具 V {0} 作者：梁昊", versionCode);
            ChangeButton(true);
        }
        private void SetValue(bool isSend, string operate, string content)
        {
            if (!this.InvokeRequired)
            {
                if (this.listView1.Items.Count > 25)
                    this.listView1.Items.Clear();

                ListViewItem Item = new ListViewItem();
                Item.ImageIndex = isSend ? 1 : 0;
                Item.Text = operate;
                Item.SubItems.Add(DateTime.Now.ToLongTimeString());
                Item.SubItems.Add(content);
                Item.Checked = isSend;
                this.listView1.Items.Insert(0, Item);
            }
            else
            {
                this.Invoke(setTextCallBack, new object[] { isSend, operate, content });
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string ip = this.textBox1.Text.Trim();
            if (ip.Length == 0)
            {
                MessageBox.Show("IP不能为空!", "温馨提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            if (!ClientTool.MatchIpAddress(ip))
            {
                if (!ClientTool.MatchDomain(ip))
                {
                    MessageBox.Show("你丫的，填个IP都错，搞个毛线!", "我要吐槽"
                        , MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }
            }

            ChangeLastLabel();

            this.checkBox1.Checked = false;
            int port = int.Parse(this.numericUpDown1.Value.ToString());
            clientSocket = new ClientSocket();
            ThreadPool.SetMaxThreads(5, 5);
            if (clientSocket.Start(ip, port, this, this.textBox4.Text, GetUseType(this.comboBox1)))
            {
                SocketConnectModel socketConnectModel = new SocketConnectModel()
                {
                    ip = this.textBox1.Text.Trim(),
                    port = int.Parse(this.numericUpDown1.Value.ToString())
                };
                XmlUtil.ObjectSerialXml(Environment.CurrentDirectory, "SocketParamer", socketConnectModel);
            }
        }

        private OperatorEnum GetOperatorEnum()
        {
            OperatorEnum operatorEnum;
            switch (this.comboBox3.SelectedIndex)
            {
                case 0:
                    operatorEnum = OperatorEnum.NO_FORWARD;
                    break;
                case 1:
                    operatorEnum = OperatorEnum.LESSTHAN;
                    break;
                case 2:
                    operatorEnum = OperatorEnum.LESSTHAN_EQUALTO;
                    break;
                case 3:
                    operatorEnum = OperatorEnum.EQUALTO;
                    break;
                case 4:
                    operatorEnum = OperatorEnum.BIGIN_EQUALTO;
                    break;
                case 5:
                    operatorEnum = OperatorEnum.BIGIN;
                    break;
                case 6:
                    operatorEnum = OperatorEnum.TO;
                    break;
                default:
                    operatorEnum = OperatorEnum.ALL;
                    break;
            }
            return operatorEnum;
        }
        private UseTypeEnum GetUseType(ComboBox comboBox)
        {
            UseTypeEnum useTypeEnum;
            switch (comboBox.SelectedIndex)
            {
                case 0:
                    useTypeEnum = UseTypeEnum.TEN;
                    break;
                case 1:
                    useTypeEnum = UseTypeEnum.ELEVEN;
                    break;
                case 2:
                    useTypeEnum = UseTypeEnum.TWELVE;
                    break;
                case 3:
                    useTypeEnum = UseTypeEnum.THIRTEEN;
                    break;
                case 4:
                    useTypeEnum = UseTypeEnum.FOURTEEN;
                    break;
                case 5:
                    useTypeEnum = UseTypeEnum.FIFTEEN;
                    break;
                case 6:
                    useTypeEnum = UseTypeEnum.SIXTEEN;
                    break;
                case 7:
                    useTypeEnum = UseTypeEnum.SEVENTEEN;
                    break;
                case 8:
                    useTypeEnum = UseTypeEnum.EIGHTEEN;
                    break;
                case 9:
                    useTypeEnum = UseTypeEnum.NINETEEN;
                    break;
                case 10:
                    useTypeEnum = UseTypeEnum.TWENTY;
                    break;
                default:
                    useTypeEnum = UseTypeEnum.TEN;
                    break;
            }
            return useTypeEnum;
        }
        private void SendMessage(string content)
        {
            SetValue(true, "发送", content);
        }
        private void ReceiveMessage(string content)
        {
            SetValue(false, "收到", content);
        }

        private void button2_Click(object sender, EventArgs e)
        {
            try
            {
                this.textBox2.Clear();
                this.timer1.Enabled = false;
                string taskId = null;
                clientSocket.SetStopBefore();
                if (clientSocket.WriteExit(out taskId))
                {
                    Thread.Sleep(200);
                    Application.DoEvents();
                    clientSocket.Close();
                }
            }
            catch (Exception error)
            {
                MessageBox.Show(error.Message);
            }
        }
        private bool WriteMessage(string content, out string taskId)
        {
            taskId = null;
            content = content.Trim();
            if (content != null && content.Length > 0)
                return clientSocket.WriteMessage(content, out taskId, GetOperatorEnum(), GetUseType(this.comboBox2));
            else
                return false;
        }
        private void Send(string content)
        {
            try
            {
                string taskId = null;
                if (!WriteMessage(content, out taskId))
                {
                    SendMessage("发送消息失败了;");
                }
                else
                {
                    SetLastDateTime(this.label13, 0, DateTime.Now);
                    SendMessage(string.Format("任务Id：{0}，内容：{1}"
                        , taskId
                        , content));
                }
            }
            catch (Exception ex)
            {
                ReceiveMessage(string.Format("[错误信息]：{0}", ex.Message));
            }
        }

        private void SendAllMessage()
        {
            if (this.textBox2.Text == null || this.textBox2.Text.Length == 0)
            {
                MessageBox.Show("消息不能为空！");
                return;
            }
            if (this.comboBox3.SelectedIndex == 6)
            {
                Form_UseId form_UseId = new Form_UseId();
                if (form_UseId.ShowDialog() == DialogResult.OK)
                {
                    Send(form_UseId.userId + this.textBox2.Text);
                }
                form_UseId.Close();
                form_UseId.Dispose();
            }
            else
            {
                Send(this.textBox2.Text);
            }
        }
        private void button3_Click(object sender, EventArgs e)
        {
            SendAllMessage();
        }

        public void SocketConnectorClose()
        {
            ReceiveMessage("断开服务器成功...");
            ChangeButton(true);
        }

        public void SocketConnectorSuccess(string ip, int port)
        {
            ReceiveMessage(string.Format("连接服务器[{0}:{1}]成功..."
                , ip
                , port));
            ChangeButton(false);
            if (this.checkBox3.Checked)
            {
                this.timer2.Enabled = true;
            }
        }

        public void SocketReceiveMessage(byte[] array)
        {
            #region 保存收到的数据
            if (this.checkBox2.Checked)
            {
                WriteModel writeModel = new WriteModel();
                writeModel.Path = this.path;
                writeModel.dateTime = DateTime.Now;
                writeModel.array = array;
                ThreadPool.QueueUserWorkItem(ThreadWriteMessage, writeModel);
            }
            #endregion

            string returnMessage;
            ClientModel clientModel = ClientTool.GetClientMessage(array, out returnMessage);
            if (clientModel != null)
            {
                string message;
                if (clientModel.GetFunctionCode() == (byte)FunctionEnum.SEND_HEART)
                    message = "得到服务端心跳包";
                else
                    message = string.Format("任务Id：{0}，内容：{1}"
                    , clientModel.GetTaskId()
                    , clientModel.GetContent());
                ReceiveMessage(message);
            }
            else
            {
                ReceiveMessage(returnMessage);
            }

            SetLastDateTime(this.label11, -1, DateTime.Now);
        }

        public void SocketError(string error)
        {
            ReceiveMessage(error);
            ChangeHeart();
            ChangeButton(true);
        }

        private void button4_Click(object sender, EventArgs e)
        {
            if (this.listView1.Items.Count > 0)
                this.listView1.Items.Clear();
        }

        private void textBox2_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                SendAllMessage();
            }
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            if (isBegin)
            {
                if (this.checkBox1.Checked)
                {
                    if (this.comboBox3.SelectedIndex == 6)
                    {
                        MessageBox.Show("转发类型为[TO]时，不能自动发送！");
                        return;
                    }
                    if (!this.timer1.Enabled)
                    {
                        this.timer1.Enabled = true;
                    }
                }
                else
                {
                    this.timer1.Enabled = false;
                }
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            this.timer1.Enabled = false;
            this.timer1.Interval = int.Parse(this.numericUpDown2.Value.ToString()) * 1000;
            if (this.textBox2.Text.Trim().Length > 0)
            {
                Send(this.textBox2.Text);
            }
            this.timer1.Enabled = true;
        }

        private void button5_Click(object sender, EventArgs e)
        {
            if (Directory.Exists(path))
                Directory.Delete(path, true);
        }

        private void button6_Click(object sender, EventArgs e)
        {
            if (Directory.Exists(path))
                System.Diagnostics.Process.Start(path);
            else
                MessageBox.Show(string.Format("日志文件夹不存在!\r\n路径：{0}", path)
                    , "温馨提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        private void ThreadWriteMessage(object message)
        {
            WriteModel writeModel = message as WriteModel;
            string fileName = writeModel.dateTime.ToString("yyyyMMddhhmmss");
            ClientTool.WriteTxt(writeModel.Path, fileName, writeModel.array);
        }

        private void checkBox2_CheckedChanged(object sender, EventArgs e)
        {
            if (isBegin)
                this.button5.Enabled = !this.checkBox2.Checked;
        }

        public void SocketIdentityError(string errorMessage)
        {
            ReceiveMessage(errorMessage);
        }

        private void button7_Click(object sender, EventArgs e)
        {
            string taskId = null;
            if (!WriteGroup(this.textBox3.Text, out taskId, true))
            {
                SocketError(string.Format("任务Id：{0}，内容：{1}"
                    , taskId
                    , "入群[" + this.textBox3.Text + "]"));
            }
            else
            {
                SetLastDateTime(this.label13, 0, DateTime.Now);
                SendMessage(string.Format("任务Id：{0}，内容：{1}"
                    , taskId
                    , "入群[" + this.textBox3.Text + "]"));
            }
        }

        private void ChangeHeart()
        {
            isHeart = !isHeart;
            if (isHeart)
                clientSocket.StartHeart();
            else
                clientSocket.StopHeart();
            this.button10.Text = isHeart ? "停止心跳" : "发出心跳";
        }

        private void button10_Click(object sender, EventArgs e)
        {
            ChangeHeart();
        }

        private void timer2_Tick(object sender, EventArgs e)
        {
            this.timer2.Enabled = false;
            ChangeHeart();
        }

        private void button8_Click(object sender, EventArgs e)
        {
            string taskId = null;
            if (!WriteGroup(this.textBox3.Text, out taskId, false))
            {
                SocketError(string.Format("任务Id：{0}，内容：{1}"
                    , taskId
                    , "出群[" + this.textBox3.Text + "]"));
            }
            else
            {
                SendMessage(string.Format("任务Id：{0}，内容：{1}"
                    , taskId
                    , "出群[" + this.textBox3.Text + "]"));
            }
        }
        private bool WriteGroup(string content, out string taskId, bool isInto)
        {
            taskId = null;
            content = content.Trim();
            FunctionEnum functionEnum = isInto ? FunctionEnum.INTO_GROUP : FunctionEnum.OUT_GROUP;
            if (content != null && content.Length > 0)
                return clientSocket.WriteMessage(content, out taskId, functionEnum, OperatorEnum.EQUALTO, UseTypeEnum.TEN);
            else
                return false;
        }

        public void SocketHeart(DateTime lastHeartSendTime)
        {
            SetLastDateTime(this.label15, 1, lastHeartSendTime);
        }
    }
}
